package com.yuan.springcloud.user.exception;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.yuan.springcloud.common.exception.ErrorEnum;
import com.yuan.springcloud.common.exception.ParamValidException;
import com.yuan.springcloud.common.exception.ServiceException;
import com.yuan.springcloud.common.web.bean.ParamValidRs;
import com.yuan.springcloud.common.web.bean.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @author YouYuan
 * @date 2020/8/18 22:19
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理参数校验异常，生成友好的提示信息给用户（包含所有校验不通过的属性与错误提示）
     * @param ex
     * @return
     */
    @ExceptionHandler(ParamValidException.class)
    @ResponseBody
    public Result resolveConstraintViolationException(ParamValidException ex){
        Result errorResult = Result.error(ErrorEnum.PARAMS_VALID_ERR);
        Set<ConstraintViolation<?>> constraintViolations = (Set<ConstraintViolation<?>>) ex.getData();
        if (CollUtil.isNotEmpty(constraintViolations)) {
            String msg = null;
            List<ParamValidRs> paramValidRsList = Lists.newArrayList();
            for (ConstraintViolation violation : constraintViolations) {
                String message = violation.getMessage();
                String property = violation.getPropertyPath().toString();
                ParamValidRs paramValidRs = ParamValidRs.builder().property(property).message(message).build();
                paramValidRsList.add(paramValidRs);
                if (StrUtil.isBlank(msg)) {
                    // 默认最外层的msg取第一条提示，需要完整提示由前端根据data返回的所有校验信息中获取
                    msg = message;
                }
            }
            errorResult.setErrMsg(msg);
            errorResult.setData(paramValidRsList);
        } else {
            errorResult.setErrMsg(ex.getMessage());
        }
        return errorResult;
    }

    /**
     * 自动捕获@Valid抛出的参数校验异常，封装后进行返回
     * @param ex
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Result resolveConstraintViolationException(MethodArgumentNotValidException ex){
        BindingResult bindingResult = ex.getBindingResult();
        Result errorResult = Result.error(ErrorEnum.PARAMS_VALID_ERR);
        String msg = null;
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        List<ParamValidRs> paramValidRsList = Lists.newArrayList();
        for (FieldError error : fieldErrors) {
            String property = error.getField();
            String message = error.getDefaultMessage();
            ParamValidRs paramValidRs = ParamValidRs.builder().property(property).message(message).build();
            paramValidRsList.add(paramValidRs);
            if (StrUtil.isBlank(msg)) {
                // 默认最外层的msg取第一条提示，需要完整提示由前端根据data返回的所有校验信息中获取
                msg = message;
            }
        }
        errorResult.setErrMsg(msg);
        errorResult.setData(paramValidRsList);
        return errorResult;
    }

}
